Skip to content

Comments

Fix memory leak in MainlineVersionStrategy#4809

Merged
arturcic merged 4 commits intoGitTools:mainfrom
sanelson:bugfix/memory-leak-mainline-strategy
Jan 31, 2026
Merged

Fix memory leak in MainlineVersionStrategy#4809
arturcic merged 4 commits intoGitTools:mainfrom
sanelson:bugfix/memory-leak-mainline-strategy

Conversation

@sanelson
Copy link
Contributor

@sanelson sanelson commented Jan 30, 2026

Fixes

  • Remove ToArray() loop to prevent exponential array growth
  • Add caching to GetCommitsWasBranchedFrom to avoid redundant calculations
  • Fixes OOM kills on ADO agents with large repos

Description

Having memory leak issues with gitversion 6.3.x - 6.5.x. Runs fine locally (Ubuntu 24.04.3 LTS) but when running via an Azure DevOps agent (Ubuntu 22.04.5 LTS) against the same repo it quickly uses all memory on the agent and then the gitversion process is OOM killed.

Some stats on the repo which triggers this issue may be relevant for others having the same problem:

  • 446 total branches
  • 183 branches converge on single commits deep in history
  • 15,356 total commits with 1,544 merges
  • 100% merge density in recent history (last 100 commits all merges)

Note: I used Claude Sonnet 4.5 to assist with the issue analysis, code patch and test case creation.

Related Issue

Resolves #4418

Motivation and Context

How Has This Been Tested?

As a few others stated in #4418 I was unable to replicate this issue running locally. The severe memory leak only seemed to occur when running GitVersion from one of our custom Ubuntu ADO agents.

I created a sanitized version of our repository that I was going to share in this PR but the obfuscation process caused the issue to disappear and I was unable to replicate the memory leak with the sanitized repo. Instead I customized the ADO pipeline to show detailed information about the pre-patch memory leak. And a subsequent run with the patch applied with a comparison between the two.

Since I have not found a way to replicate the failure scenario outside of our very specific repo and ADO agent config it didn't make much sense for me to create a traditional test case for this change.

Here are the details from the most recent test pipeline run.

================================================================================
                    MEMORY LEAK FIX VALIDATION REPORT
                     infrastructure-aks-gitversion
                  (13,245 commits - 1,404 merges - 446 branches)
================================================================================

RESULTS SUMMARY

  WITHOUT FIX (commit: memory-leak-before-fix)
     Exit Code:     137
     Status:        OOM
     Memory Used:   30.4 GB
     Runtime:       0:49.14

  WITH FIX (commit: memory-leak-with-fix)
     Exit Code:     0
     Status:        SUCCESS
     Memory Used:   217 MB
     Runtime:       0:29.80

REPRODUCIBILITY

     Tags:   memory-leak-before-fix | memory-leak-with-fix
     Repo:   https://github.com/sanelson/GitVersion.git
     Branch: bugfix/memory-leak-mainline-strategy

================================================================================

Memory Leak Failure Run Detail

##[section]Starting: Test WITHOUT fix (should timeout or OOM)
==============================================================================
Task         : Bash
Description  : Run a Bash script on macOS, Linux, or Windows
Version      : 3.268.1
Author       : Microsoft Corporation
Help         : https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/bash
==============================================================================
Generating script.
========================== Starting Command Output ===========================
[command]/usr/bin/bash /agent/_work/_temp/cd81f2c8-95c1-4200-8e97-1bc508fa4939.sh
=== Testing WITHOUT fix (should timeout or OOM) ===
Note: switching to 'memory-leak-before-fix'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at d62573b79 chore(sonarlint): Add SonarCloud project configuration
  Determining projects to restore...
  Restored /agent/_work/1/GitVersion/src/GitVersion.Configuration/GitVersion.Configuration.csproj (in 1.6 sec).
  Restored /agent/_work/1/GitVersion/src/GitVersion.BuildAgents/GitVersion.BuildAgents.csproj (in 1.6 sec).
  Restored /agent/_work/1/GitVersion/src/GitVersion.Core/GitVersion.Core.csproj (in 1.6 sec).
  Restored /agent/_work/1/GitVersion/src/GitVersion.Output/GitVersion.Output.csproj (in 1.6 sec).
  Restored /agent/_work/1/GitVersion/src/GitVersion.LibGit2Sharp/GitVersion.LibGit2Sharp.csproj (in 1.6 sec).
  Restored /agent/_work/1/GitVersion/src/GitVersion.App/GitVersion.App.csproj (in 1.6 sec).
  GitVersion.Core -> /agent/_work/1/GitVersion/src/GitVersion.Core/bin/Release/net10.0/GitVersion.Core.dll
  GitVersion.BuildAgents -> /agent/_work/1/GitVersion/src/GitVersion.BuildAgents/bin/Release/net10.0/GitVersion.BuildAgents.dll
  GitVersion.Output -> /agent/_work/1/GitVersion/src/GitVersion.Output/bin/Release/net10.0/GitVersion.Output.dll
  GitVersion.LibGit2Sharp -> /agent/_work/1/GitVersion/src/GitVersion.LibGit2Sharp/bin/Release/net10.0/GitVersion.LibGit2Sharp.dll
  GitVersion.Configuration -> /agent/_work/1/GitVersion/src/GitVersion.Configuration/bin/Release/net10.0/GitVersion.Configuration.dll
  GitVersion.App -> /agent/_work/1/GitVersion/src/GitVersion.App/bin/Release/net10.0/gitversion.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:08.78
Running GitVersion WITHOUT fix...
Working directory: /agent/_work/1/s
Timeout: 120 seconds
##[warning]Free memory is lower than 5%; Currently used: 99.68%
##[warning]Free memory is lower than 5%; Currently used: 99.68%
##[warning]Free memory is lower than 5%; Currently used: 99.68%
##[warning]Free memory is lower than 5%; Currently used: 99.68%
##[warning]Free memory is lower than 5%; Currently used: 99.68%
##[warning]Free memory is lower than 5%; Currently used: 99.68%
Exit code: 137
OOM: Process killed by memory limit
=== Memory stats (if available) ===
	Maximum resident set size (kbytes): 31910268

=== GitVersion Error Output (first 30 lines) ===
INFO [26-01-30 19:21:55:15] Working directory: /agent/_work/1/s
INFO [26-01-30 19:21:55:18] Project root is: /agent/_work/1/s/
INFO [26-01-30 19:21:55:18] DotGit directory is: /agent/_work/1/s/.git
INFO [26-01-30 19:21:55:18] Branch from build environment: refs/heads/gitversion-upgrade-testing
INFO [26-01-30 19:21:55:18] -< Begin: Normalizing git directory for branch 'refs/heads/gitversion-upgrade-testing' >-
  INFO [26-01-30 19:21:55:22] One remote found (origin -> 'https://<REDACTED>@dev.azure.com/<REDACTED>/<REDACTED>/_git/<REDACTED>').
  INFO [26-01-30 19:21:55:22] Skipping fetching, if GitVersion does not calculate your version as expected you might need to allow fetching or use dynamic repositories
  INFO [26-01-30 19:21:55:47] Creating local branch gitversion-upgrade-testing
  INFO [26-01-30 19:21:55:52] Creating local branch from remote tracking 'refs/remotes/origin/11074'.
  INFO [26-01-30 19:21:55:53] Creating local branch from remote tracking 'refs/remotes/origin/11074b'.
  INFO [26-01-30 19:21:55:53] Creating local branch from remote tracking 'refs/remotes/origin/15.3.0-main'.
  INFO [26-01-30 19:21:55:54] Creating local branch from remote tracking 'refs/remotes/origin/15.78.3'.
  INFO [26-01-30 19:21:55:54] Creating local branch from remote tracking 'refs/remotes/origin/17.1.1-patch'.
  INFO [26-01-30 19:21:55:54] Creating local branch from remote tracking 'refs/remotes/origin/17.3.1-patch'.
  INFO [26-01-30 19:21:55:54] Creating local branch from remote tracking 'refs/remotes/origin/18.1.2-main'.
  INFO [26-01-30 19:21:55:54] Creating local branch from remote tracking 'refs/remotes/origin/8508g'.
  INFO [26-01-30 19:21:55:54] Creating local branch from remote tracking 'refs/remotes/origin/<REDACTED>'.
  INFO [26-01-30 19:21:55:55] Creating local branch from remote tracking 'refs/remotes/origin/<REDACTED>'.
  INFO [26-01-30 19:21:55:55] Creating local branch from remote tracking 'refs/remotes/origin/<REDACTED>'.
  INFO [26-01-30 19:21:55:55] Creating local branch from remote tracking 'refs/remotes/origin/<REDACTED>'.
  INFO [26-01-30 19:21:55:55] Creating local branch from remote tracking 'refs/remotes/origin/<REDACTED>'.
  INFO [26-01-30 19:21:55:55] Creating local branch from remote tracking 'refs/remotes/origin/<REDACTED>'.
  INFO [26-01-30 19:21:55:56] Creating local branch from remote tracking 'refs/remotes/origin/<REDACTED>'.
  INFO [26-01-30 19:21:55:56] Creating local branch from remote tracking 'refs/remotes/origin/<REDACTED>'.
  INFO [26-01-30 19:21:55:56] Creating local branch from remote tracking 'refs/remotes/origin/<REDACTED>'.
  INFO [26-01-30 19:21:55:56] Creating local branch from remote tracking 'refs/remotes/origin/<REDACTED>'.
  INFO [26-01-30 19:21:55:57] Creating local branch from remote tracking 'refs/remotes/origin/<REDACTED>'.
  INFO [26-01-30 19:21:55:57] Creating local branch from remote tracking 'refs/remotes/origin/<REDACTED>'.
  INFO [26-01-30 19:21:55:57] Creating local branch from remote tracking 'refs/remotes/origin/<REDACTED>'.
  INFO [26-01-30 19:21:55:57] Creating local branch from remote tracking 'refs/remotes/origin/<REDACTED>'.

=== GitVersion Error Output (last 30 lines) ===
          INFO [26-01-30 19:22:24:83] Found merge base of ''008514d' - Merged PR 24019: <REDACTED>'
          INFO [26-01-30 19:22:24:83] Merge base of 'develop' and 'origin/<REDACTED>' is ''008514d' - Merged PR 24019: <REDACTED>'
        INFO [26-01-30 19:22:24:83] -< End: Finding merge base between 'develop' and 'origin/<REDACTED>'. (Took: 3.36ms) >-
      INFO [26-01-30 19:22:24:84] -< End: Finding branches source of 'develop' (Took: 18,832.92ms) >-
Command terminated by signal 9
	Command being timed: "/agent/_work/1/GitVersion/src/GitVersion.App/bin/Release/net10.0/gitversion --roll-forward Major /agent/_work/1/s /output json /l console"
	User time (seconds): 39.07
	System time (seconds): 13.21
	Percent of CPU this job got: 106%
	Elapsed (wall clock) time (h:mm:ss or m:ss): 0:49.14
	Average shared text size (kbytes): 0
	Average unshared data size (kbytes): 0
	Average stack size (kbytes): 0
	Average total size (kbytes): 0
	Maximum resident set size (kbytes): 31910268
	Average resident set size (kbytes): 0
	Major (requiring I/O) page faults: 1476
	Minor (reclaiming a frame) page faults: 2979924
	Voluntary context switches: 5585
	Involuntary context switches: 410
	Swaps: 0
	File system inputs: 402896
	File system outputs: 40232
	Socket messages sent: 0
	Socket messages received: 0
	Signals delivered: 0
	Page size (bytes): 4096
	Exit status: 0
Exit code: 137
OOM: Process killed by memory limit

##[section]Finishing: Test WITHOUT fix (should timeout or OOM)

Memory Leak Fix Run Detail

##[section]Starting: Test WITH fix (should succeed)
==============================================================================
Task         : Bash
Description  : Run a Bash script on macOS, Linux, or Windows
Version      : 3.268.1
Author       : Microsoft Corporation
Help         : https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/bash
==============================================================================
Generating script.
========================== Starting Command Output ===========================
[command]/usr/bin/bash /agent/_work/_temp/13b9d5e5-d664-49be-9d2e-79c57a383427.sh
=== Testing WITH fix (should succeed) ===
Previous HEAD position was d62573b79 chore(sonarlint): Add SonarCloud project configuration
HEAD is now at 8fae7d8e2 Use canonical identifier for cache key to avoid name collisions
  Determining projects to restore...
  All projects are up-to-date for restore.
  GitVersion.Core -> /agent/_work/1/GitVersion/src/GitVersion.Core/bin/Release/net10.0/GitVersion.Core.dll
  GitVersion.BuildAgents -> /agent/_work/1/GitVersion/src/GitVersion.BuildAgents/bin/Release/net10.0/GitVersion.BuildAgents.dll
  GitVersion.Configuration -> /agent/_work/1/GitVersion/src/GitVersion.Configuration/bin/Release/net10.0/GitVersion.Configuration.dll
  GitVersion.Output -> /agent/_work/1/GitVersion/src/GitVersion.Output/bin/Release/net10.0/GitVersion.Output.dll
  GitVersion.LibGit2Sharp -> /agent/_work/1/GitVersion/src/GitVersion.LibGit2Sharp/bin/Release/net10.0/GitVersion.LibGit2Sharp.dll
  GitVersion.App -> /agent/_work/1/GitVersion/src/GitVersion.App/bin/Release/net10.0/gitversion.dll

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:06.51
Running GitVersion WITH fix...
Working directory: /agent/_work/1/s
Exit code: 0
SUCCESS: Process completed successfully
=== Memory stats ===
	Maximum resident set size (kbytes): 218676

=== GitVersion Success Output (first 30 lines) ===
INFO [26-01-30 21:02:28:96] Working directory: /agent/_work/1/s
INFO [26-01-30 21:02:29:00] Project root is: /agent/_work/1/s/
INFO [26-01-30 21:02:29:00] DotGit directory is: /agent/_work/1/s/.git
INFO [26-01-30 21:02:29:00] Branch from build environment: refs/heads/gitversion-upgrade-testing
INFO [26-01-30 21:02:29:00] -< Begin: Normalizing git directory for branch 'refs/heads/gitversion-upgrade-testing' >-
  INFO [26-01-30 21:02:29:04] One remote found (origin -> 'https://<REDACTED>@dev.azure.com/<REDACTED>/<REDACTED>/_git/<REDACTED>').
  INFO [26-01-30 21:02:29:04] Skipping fetching, if GitVersion does not calculate your version as expected you might need to allow fetching or use dynamic repositories
  INFO [26-01-30 21:02:32:13] Updating local branch gitversion-upgrade-testing to point at 18b5b76
  INFO [26-01-30 21:02:32:21] Skipping update of 'refs/remotes/origin/11074' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:21] Skipping update of 'refs/remotes/origin/11074b' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:21] Skipping update of 'refs/remotes/origin/15.3.0-main' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:21] Skipping update of 'refs/remotes/origin/15.78.3' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:21] Skipping update of 'refs/remotes/origin/17.1.1-patch' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:22] Skipping update of 'refs/remotes/origin/17.3.1-patch' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:22] Skipping update of 'refs/remotes/origin/18.1.2-main' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:22] Skipping update of 'refs/remotes/origin/8508g' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:22] Skipping update of 'refs/remotes/origin/<REDACTED>' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:22] Skipping update of 'refs/remotes/origin/<REDACTED>' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:22] Skipping update of 'refs/remotes/origin/<REDACTED>' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:22] Skipping update of 'refs/remotes/origin/<REDACTED>' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:22] Skipping update of 'refs/remotes/origin/<REDACTED>' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:22] Skipping update of 'refs/remotes/origin/<REDACTED>' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:22] Skipping update of 'refs/remotes/origin/<REDACTED>' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:22] Skipping update of 'refs/remotes/origin/<REDACTED>' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:23] Skipping update of 'refs/remotes/origin/<REDACTED>' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:23] Skipping update of 'refs/remotes/origin/<REDACTED>' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:23] Skipping update of 'refs/remotes/origin/<REDACTED>' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:23] Skipping update of 'refs/remotes/origin/<REDACTED>' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:23] Skipping update of 'refs/remotes/origin/<REDACTED>' as it already matches the remote ref.
  INFO [26-01-30 21:02:32:23] Skipping update of 'refs/remotes/origin/<REDACTED>' as it already matches the remote ref.

=== GitVersion Success Output (last 50 lines) ===
  "AssemblySemVer": "24.7.0.0",
  "BranchName": "gitversion-upgrade-testing",
  "BuildMetaData": null,
  "CommitDate": "2026-01-30",
  "CommitsSinceVersionSource": 1,
  "EscapedBranchName": "gitversion-upgrade-testing",
  "FullBuildMetaData": "Branch.gitversion-upgrade-testing.Sha.18b5b76ed109345b97b42ece52f8eba8b233c7fa",
  "FullSemVer": "24.7.0-27",
  "InformationalVersion": "24.7.0-27+Branch.gitversion-upgrade-testing.Sha.18b5b76ed109345b97b42ece52f8eba8b233c7fa",
  "Major": 24,
  "MajorMinorPatch": "24.7.0",
  "Minor": 7,
  "Patch": 0,
  "PreReleaseLabel": "",
  "PreReleaseLabelWithDash": "",
  "PreReleaseNumber": 27,
  "PreReleaseTag": "27",
  "PreReleaseTagWithDash": "-27",
  "SemVer": "24.7.0-27",
  "Sha": "18b5b76ed109345b97b42ece52f8eba8b233c7fa",
  "ShortSha": "18b5b76",
  "UncommittedChanges": 0,
  "VersionSourceSha": "2bedf4001aa7c57219cc30bc8a7f4be8540adf77",
  "WeightedPreReleaseNumber": 55027
}
	Command being timed: "/agent/_work/1/GitVersion/src/GitVersion.App/bin/Release/net10.0/gitversion --roll-forward Major /agent/_work/1/s /output json /l console"
	User time (seconds): 27.95
	System time (seconds): 1.65
	Percent of CPU this job got: 99%
	Elapsed (wall clock) time (h:mm:ss or m:ss): 0:29.68
	Average shared text size (kbytes): 0
	Average unshared data size (kbytes): 0
	Average stack size (kbytes): 0
	Average total size (kbytes): 0
	Maximum resident set size (kbytes): 218676
	Average resident set size (kbytes): 0
	Major (requiring I/O) page faults: 238
	Minor (reclaiming a frame) page faults: 46082
	Voluntary context switches: 12714
	Involuntary context switches: 80
	Swaps: 0
	File system inputs: 127328
	File system outputs: 1392
	Socket messages sent: 0
	Socket messages received: 0
	Signals delivered: 0
	Page size (bytes): 4096
	Exit status: 0
Exit code: 0
SUCCESS: Process completed successfully

##[section]Finishing: Test WITH fix (should succeed)

ADO Agent Test Environment Specs

dotnet --version
10.0.101
-------------------------------
git --version
git version 2.52.0
-------------------------------
free -h
               total        used        free      shared  buff/cache   available
Mem:            31Gi       811Mi        26Gi        58Mi       4.4Gi        30Gi
Swap:          4.0Gi          0B       4.0Gi
-------------------------------
mpstat
Linux 6.8.0-1041-azure (ubuntuplatform00013E) 	01/30/26 	_x86_64_	(8 CPU)

19:21:32     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
19:21:32     all    3.44    0.43    2.27    1.10    0.00    0.07    0.00    0.00    0.00   92.68
-------------------------------
ulimit -a (resource limits)
real-time non-blocking time  (microseconds, -R) unlimited
core file size              (blocks, -c) 0
data seg size               (kbytes, -d) unlimited
scheduling priority                 (-e) 0
file size                   (blocks, -f) unlimited
pending signals                     (-i) 128345
max locked memory           (kbytes, -l) 4107992
max memory size             (kbytes, -m) unlimited
open files                          (-n) 65536
pipe size                (512 bytes, -p) 8
POSIX message queues         (bytes, -q) 819200
real-time priority                  (-r) 0
stack size                  (kbytes, -s) 16384
cpu time                   (seconds, -t) unlimited
max user processes                  (-u) 128345
virtual memory              (kbytes, -v) unlimited
file locks                          (-x) unlimited
-------------------------------
cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.5 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.5 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="[https://www.ubuntu.com/"](https://www.ubuntu.com/%22)
SUPPORT_URL="[https://help.ubuntu.com/"](https://help.ubuntu.com/%22)
BUG_REPORT_URL="[https://bugs.launchpad.net/ubuntu/"](https://bugs.launchpad.net/ubuntu/%22)
PRIVACY_POLICY_URL="[https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"](https://www.ubuntu.com/legal/terms-and-policies/privacy-policy%22)
UBUNTU_CODENAME=jammy

Git config

safe.directory=*
filter.lfs.clean=git-lfs clean -- %f
filter.lfs.smudge=git-lfs smudge -- %f
filter.lfs.process=git-lfs filter-process
filter.lfs.required=true
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.longpaths=true
remote.origin.url=<REDACTED>
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
extensions.worktreeconfig=true
gc.auto=0
http.version=HTTP/1.1
core.sparsecheckout=false
core.sparsecheckoutcone=false
index.sparse=false

Gitversion Config

assembly-versioning-scheme: MajorMinorPatch
assembly-file-versioning-scheme: MajorMinorPatch
tag-prefix: '[vV]?'
version-in-branch-pattern: (?<version>[vV]?\d+(\.\d+)?(\.\d+)?).*
major-version-bump-message: \+semver:\s?(breaking|major)
minor-version-bump-message: \+semver:\s?(feature|minor)
patch-version-bump-message: \+semver:\s?(fix|patch)
no-bump-message: \+semver:\s?(none|skip)
tag-pre-release-weight: 60000
commit-date-format: yyyy-MM-dd
merge-message-formats: {}
update-build-number: true
semantic-version-format: Strict
strategies:
- Mainline
branches:
  develop:
    mode: ContinuousDelivery
    label: alpha
    increment: Minor
    prevent-increment:
      when-current-commit-tagged: false
    track-merge-target: true
    track-merge-message: true
    regex: ^dev(elop)?(ment)?$
    source-branches:
    - main
    is-source-branch-for: []
    tracks-release-branches: true
    is-release-branch: false
    is-main-branch: false
    pre-release-weight: 0
  main:
    mode: ContinuousDelivery
    label: ''
    increment: None
    prevent-increment:
      of-merged-branch: true
    track-merge-target: false
    track-merge-message: true
    regex: .*
    source-branches: []
    is-source-branch-for: []
    tracks-release-branches: false
    is-release-branch: false
    is-main-branch: true
    pre-release-weight: 55000
  release:
    mode: ManualDeployment
    label: beta
    increment: Minor
    prevent-increment:
      of-merged-branch: true
      when-current-commit-tagged: false
    track-merge-target: false
    regex: ^releases?[\/-](?<BranchName>.+)
    source-branches:
    - main
    - support
    is-source-branch-for: []
    tracks-release-branches: false
    is-release-branch: true
    is-main-branch: false
    pre-release-weight: 30000
  feature:
    mode: ManualDeployment
    label: '{BranchName}'
    increment: Inherit
    prevent-increment:
      when-current-commit-tagged: false
    track-merge-message: true
    regex: ^features?[\/-](?<BranchName>.+)
    source-branches:
    - develop
    - main
    - release
    - support
    - hotfix
    is-source-branch-for: []
    is-main-branch: false
    pre-release-weight: 30000
  pull-request:
    mode: ContinuousDelivery
    label: PullRequest{Number}
    increment: Inherit
    prevent-increment:
      of-merged-branch: true
      when-current-commit-tagged: false
    track-merge-message: true
    regex: ^(pull-requests|pull|pr)[\/-](?<Number>\d*)
    source-branches:
    - develop
    - main
    - release
    - feature
    - support
    - hotfix
    is-source-branch-for: []
    pre-release-weight: 30000
  hotfix:
    mode: ManualDeployment
    label: beta
    increment: Inherit
    prevent-increment:
      when-current-commit-tagged: false
    regex: ^hotfix(es)?[\/-](?<BranchName>.+)
    source-branches:
    - main
    - support
    is-source-branch-for: []
    is-release-branch: true
    is-main-branch: false
    pre-release-weight: 30000
  support:
    label: ''
    increment: Patch
    prevent-increment:
      of-merged-branch: true
    track-merge-target: false
    regex: ^support[\/-](?<BranchName>.+)
    source-branches:
    - main
    is-source-branch-for: []
    tracks-release-branches: false
    is-release-branch: false
    is-main-branch: true
    pre-release-weight: 55000
  unknown:
    mode: ManualDeployment
    label: '{BranchName}'
    increment: Inherit
    prevent-increment:
      when-current-commit-tagged: true
    regex: (?<BranchName>.+)
    source-branches:
    - main
    - develop
    - release
    - feature
    - pull-request
    - hotfix
    - support
    is-source-branch-for: []
    is-main-branch: false
ignore:
  sha: []
  paths: []
mode: ContinuousDelivery
label: '{BranchName}'
increment: Inherit
prevent-increment:
  of-merged-branch: false
  when-branch-merged: false
  when-current-commit-tagged: true
track-merge-target: false
track-merge-message: true
commit-message-incrementing: Enabled
regex: ''
source-branches: []
is-source-branch-for: []
tracks-release-branches: false
is-release-branch: false
is-main-branch: false

Screenshots (if appropriate):

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

  - Remove ToArray() loop to prevent exponential array growth
  - Add caching to GetCommitsWasBranchedFrom to avoid redundant calculations
  - Fixes OOM kills on ADO agents with large repos
Copilot AI review requested due to automatic review settings January 30, 2026 20:12
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses excessive memory usage (up to OOM) in MainlineVersionStrategy when calculating versions for large, branch-heavy repositories by removing a pathological list-growth pattern and introducing caching to reduce repeated computations.

Changes:

  • Removed the ToArray()-based loop that could repeatedly duplicate list entries (leading to explosive growth).
  • Added a cache for GetCommitsWasBranchedFrom results to avoid redundant FindCommitBranchesBranchedFrom calls for the same branch/exclusion set.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Member

@asbjornu asbjornu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work! I've not verified your numbers, but I think MainlineVersionStrategy is well covered with tests, so as none of them breaks, this should at least not make the situation worse. I say it's worth getting this merged and into the hands of developers who've experienced GitVersion OOM.

@asbjornu asbjornu enabled auto-merge January 30, 2026 22:34
@asbjornu
Copy link
Member

@arturcic seems like a recurring problem now that PRs are halted in the Code quality results are pending for one analyzed language state. Ideas?

image

@arturcic
Copy link
Member

@sanelson mind to fix the minor sonacloud issue?

@arturcic
Copy link
Member

@arturcic seems like a recurring problem now that PRs are halted in the Code quality results are pending for one analyzed language state. Ideas?

image

might be after some changes to the rulesets I did

auto-merge was automatically disabled January 30, 2026 22:50

Head branch was pushed to by a user without write access

@arturcic
Copy link
Member

@sanelson please revert the change, seems it was a false positive

@sanelson
Copy link
Contributor Author

@sanelson please revert the change, seems it was a false positive

Sorry, I should have built locally before I committed that, lol. Changed it to use .GetValueOrDefault(). Hopefully that'll make SonarQube happy.

@sonarqubecloud
Copy link

@arturcic arturcic merged commit 54f45f9 into GitTools:main Jan 31, 2026
118 checks passed
@mergify
Copy link
Contributor

mergify bot commented Jan 31, 2026

Thank you @sanelson for your contribution!

This was referenced Feb 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ISSUE]: GitVersion sometimes takes several hours, seemingly hanging for several minutes between steps

3 participants